iT邦幫忙

0

Day 26|單元測試(Unit Testing)與 xUnit

c#
  • 分享至 

  • xImage
  •  

今日學習目標

  • 理解單元測試與整合測試的差別
  • 認識 xUnit 測試框架
  • 學會 [Fact] 與 Assert
  • 建立 TaskFlow3.Tests 測試專案
  • 測試新增及查詢任務
  • 測試使用者任務擁有權
  • 使用 dotnet test 執行自動化測試

什麼是單元測試

單元測試(Unit Testing)是針對程式中的某個方法或功能,檢查它是否產生預期結果。
https://ithelp.ithome.com.tw/upload/images/20261024/201844303G5OSZvjXb.png

單元測試與整合測試有什麼不同

https://ithelp.ithome.com.tw/upload/images/20261024/20184430wQKU5sOv01.png

建立 xUnit 測試專案

繼續使用原本的 TaskFlow3.Api,還要另外建立一個測試專案。
建立 xUnit 專案dotnet new xunit -n TaskFlow3.Tests -f net10.0
建立專案參考dotnet add .\TaskFlow3.Tests\TaskFlow3.Tests.csproj reference .\TaskFlow3.Api\TaskFlow3.Api.csproj

建立 TaskServiceTests.cs

在 VS Code 左側找到:TaskFlow3.Tests,如果裡面有範本建立的 UnitTest1.cs,可以刪除,避免留下不需要的範例,然後新增:TaskServiceTests.cs
為什麼使用 SQLite 記憶體資料庫
在TaskServiceTests.cs打上程式碼:

using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using TaskFlow3.Api.Data;
using TaskFlow3.Api.Services;
using Xunit;

namespace TaskFlow3.Tests
{
    public class TaskServiceTests
    {
        // 測試 1:新增任務
        [Fact]
        public async Task CreateAsync_ShouldSaveTask()
        {
            using var connection =
                new SqliteConnection("Data Source=:memory:");

            await connection.OpenAsync();

            var options =
                new DbContextOptionsBuilder<TaskFlowDbContext>()
                .UseSqlite(connection)
                .Options;

            using var db = new TaskFlowDbContext(options);

            await db.Database.EnsureCreatedAsync();

            var service = new TaskService(db);

            var task = await service.CreateAsync(
                "完成 C# 作業",
                "alice-id"
            );

            Assert.True(task.Id > 0);
            Assert.Equal("完成 C# 作業", task.Title);
            Assert.Equal("alice-id", task.OwnerIdentityId);

            var savedTask = await db.Tasks.FindAsync(task.Id);

            Assert.NotNull(savedTask);
        }

        // 測試 2:使用者只能查看自己的任務
        [Fact]
        public async Task GetAllAsync_ShouldFilterByOwner()
        {
            using var connection =
                new SqliteConnection("Data Source=:memory:");

            await connection.OpenAsync();

            var options =
                new DbContextOptionsBuilder<TaskFlowDbContext>()
                .UseSqlite(connection)
                .Options;

            using var db = new TaskFlowDbContext(options);

            await db.Database.EnsureCreatedAsync();

            var service = new TaskService(db);

            await service.CreateAsync("Alice 的作業", "alice-id");
            await service.CreateAsync("Bob 的作業", "bob-id");

            var aliceTasks =
                await service.GetAllAsync("alice-id");

            Assert.Single(aliceTasks);
            Assert.Equal("Alice 的作業", aliceTasks[0].Title);
            Assert.Equal("alice-id", aliceTasks[0].OwnerIdentityId);
        }

        // 測試 3:不能刪除其他人的任務
        [Fact]
        public async Task DeleteAsync_ShouldRejectOtherOwner()
        {
            using var connection =
                new SqliteConnection("Data Source=:memory:");

            await connection.OpenAsync();

            var options =
                new DbContextOptionsBuilder<TaskFlowDbContext>()
                .UseSqlite(connection)
                .Options;

            using var db = new TaskFlowDbContext(options);

            await db.Database.EnsureCreatedAsync();

            var service = new TaskService(db);

            var task = await service.CreateAsync(
                "Alice 的私人任務",
                "alice-id"
            );

            bool deleted = await service.DeleteAsync(
                task.Id,
                "bob-id"
            );

            Assert.False(deleted);

            var savedTask = await db.Tasks.FindAsync(task.Id);

            Assert.NotNull(savedTask);
        }
    }
}

執行測試

到 VS Code 終端機輸入:dotnet test .\TaskFlow3.Tests\TaskFlow3.Tests.csproj


*提醒邦友,使用第三方服務/API 時,請務必評估資安風險與隱私保護
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言